﻿/// <summary>
/// Program for images manipulation 
/// </summary>

// compile with: /unsafe
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;

/// <summary>
/// @author: Pedro Faisco n.6055 ; Pedro Caciones n. 9989
/// @date: 19/02/2013
/// @obs: Class that builds the graphic forms, buttons and handles the events.
/// </summary>
namespace _6055_9989_LP_Photoshop_2012_2013
{
    /// <summary>
    /// This class will built the Main Window
    /// </summary>
    public partial class MainWindow : Form
    {
        private Stack<Bitmap> undoStack = new Stack<Bitmap>();
        private ToolStripMenuItem old = null;
        private Color choosenColor;
        private Point fstSel;
        private bool pickColor;
        private Bitmap copyImg;
        private Rectangle Rect;
        private Brush selectionBrush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));
        private Boolean paste;

        /// <summary>
        /// Constructor class
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            this.image = new Bitmap(2, 2);
            
        }
        /// <summary>
        /// Will allow to close image file
        /// </summary>
        private void exitMenuFileItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Will allow to load image file
        /// </summary>
        private void loadMenuFileItem_Click(object sender, EventArgs e)
        {
            
              OpenFileDialog openFileDialog = new OpenFileDialog();

              openFileDialog.Filter = "BMP |*.bmp;*.dib |JPG |*.jpg | PNG | *.png | GIF | *.gif | ICO | *.ico | All Files | *.*";
              openFileDialog.RestoreDirectory = true ;
              openFileDialog.FilterIndex = 6;
              
              if(DialogResult.OK == openFileDialog.ShowDialog())
              {
                  this.imgPath = openFileDialog.FileName;
                  MemoryStream imgStream = new MemoryStream(File.ReadAllBytes(this.imgPath));
                  Image open = Image.FromStream(imgStream);
                  this.image = (Bitmap)open.Clone();
                  this.undoStack.Push((Bitmap)this.image.Clone());
                  open.Dispose();
                  this.panel1.Invalidate();                 
              }
          }

        /// <summary>
        /// Will allow to save image file
        /// </summary>
        private void saveMenuFileItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.imgPath != "")
                {
                    MessageBox.Show(this.imgPath);
                    this.image.Save(this.imgPath);
                }
                else
                {
                    this.saveAs();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        /// <summary>
        /// Will show the about box
        /// </summary>
        private void aboutMenuHelpItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("LP Photoshop \n Pedro Caciones, Pedro Faísco \n 30 Janeiro de 2013");
        }

        /// <summary>
        /// Will allow to "save as" image file
        /// </summary>
        private void saveAsMenuFileItem_Click(object sender, EventArgs e)
        {
            this.saveAs();
        }

        private void saveAs()
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog(); //Create a savefile window 

            saveFileDialog.Filter = "BMP |*.bmp;*.dib |JPG |*.jpg | PNG | *.png | GIF | *.gif | ICO | *.ico | All Files | *.*";
            saveFileDialog.RestoreDirectory = true;
            try
            {
                if (DialogResult.OK == saveFileDialog.ShowDialog())
                {
                    Image cp = (Image)this.image.Clone();

                    cp.Save(saveFileDialog.FileName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        /// <summary>
        /// Will show image colour list info
        /// </summary>
        private void btnImgInfo_Click(object sender, EventArgs e)
        {
            Dictionary<Color, int> colorDic = new Dictionary<Color, int>();
         
            for (int y = 1; y < this.image.Height; y++)
            {
                for (int x = 1; x < this.image.Width; x++)
                {
                    Color currentPixel =this.image.GetPixel(x, y);
                    if (!colorDic.ContainsKey(currentPixel))
                    {
                       colorDic.Add(currentPixel, 1); 
                    }
                    else
                        colorDic[currentPixel] = colorDic[currentPixel] + 1; 
                }
            }
            Form tempDialog = makeInfo_Form(colorDic); // form construction

            tempDialog.ShowDialog();
        }


        private ListView makeInfo_ListView(Dictionary<Color, int> dCol)
        {
            ListView listView = new ListView(); // create list view
            listView.Bounds = new Rectangle(new Point(0, 0), new Size(150, 400));
            listView.View = View.Details;   // enable list view to show items
          

            ColumnHeader column1 = new ColumnHeader();  
            column1.Text = "Repeted";
            column1.Width = 150;
           
            foreach (KeyValuePair<Color, int> pair in dCol)
            {
                ListViewItem item = new ListViewItem();
                item.BackColor = pair.Key; // sets the row cell color to color in image
                item.Text = pair.Value.ToString();
                item.ForeColor = Color.FromArgb(255 - pair.Key.A, 255 - pair.Key.R, 255 - pair.Key.G, 255 - pair.Key.B); 
                listView.Items.Add(item);
            }
            listView.Columns.Add(column1);  // Add column to the ListView
            return listView;
        }

        private Form makeInfo_Form(Dictionary<Color, int> dCol)
        {
            Form tempDialog = new Form();   // create form
            tempDialog.StartPosition = FormStartPosition.CenterScreen;
            tempDialog.Text = "Image Info";
            tempDialog.Size = new Size(160, 425);
            tempDialog.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;  // disables user window expand
            tempDialog.MaximizeBox = false;

            ListView listView = makeInfo_ListView(dCol); // calls method to build list view
            listView.Size = new Size(tempDialog.Size.Width - 16, tempDialog.Size.Height); // less 16 to let scroll bar appears

            tempDialog.Controls.Add(listView);  // adds list view to form

            return tempDialog;
        }

        /// <summary>
        /// Create a zoom options in Menu Bar
        /// </summary>
        private void zoomMenuBarItem_Click(object sender, EventArgs e)
        {
            if (this.old != null)
            {
                this.old.Checked = false;
            }
            else
                this.MenuZoomItem100.Checked = false;
            this.old = (ToolStripMenuItem)sender;
            this.changeZoom(this.old.Tag.ToString());
        }

       private void changeZoom(String zoom)
       {
           
           double z = 1;
           double.TryParse(zoom, out z);
           z = z / 100.0;
           this.Zoom = z;
           this.panel1.Invalidate();
       }

       private void btnClose_Click(object sender, EventArgs e)
       {
           this.undoStack.Push(this.image);
           this.image = new Bitmap(2, 2);
           this.panel1.Invalidate();
       }

       private void btnChooseColor_Click(object sender, EventArgs e)
       {
           this.ChooseColorDlg.AnyColor = true;
           this.ChooseColorDlg.SolidColorOnly = false;
           this.ChooseColorDlg.ShowDialog();
           this.choosenColor = this.ChooseColorDlg.Color;

       }

       private void panel1_Paint(object sender, PaintEventArgs e)
       {   
           Size imgSize = new Size((int)(this.image.Width * this.Zoom), (int)(this.image.Height * this.Zoom));
           panel1.AutoScrollMinSize = imgSize;
           e.Graphics.DrawImage(this.image, new Rectangle(this.panel1.AutoScrollPosition.X, this.panel1.AutoScrollPosition.Y, (int)(this.image.Width * this.Zoom), (int)(this.image.Height * this.Zoom)));
           if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
           {
               e.Graphics.FillRectangle(selectionBrush, Rect);
           }
       }

       private void panel1_MouseMove(object sender, MouseEventArgs e)
       {
           
           if (e.X <= this.image.Width * this.Zoom && e.Y <= this.image.Height * this.Zoom)
           {
               
               this.PosLabel.Text = string.Format("Position: {0}, {1}px", -1 * (-this.panel1.AutoScrollPosition.X - e.X), -1 * (this.panel1.AutoScrollPosition.Y - e.Y));
               Point tempEndPoint = e.Location;
               if (e.Button != MouseButtons.Left)
                   return;
               this.Rect.Location = new Point(Math.Min(this.fstSel.X, tempEndPoint.X), Math.Min(this.fstSel.Y, tempEndPoint.Y));
               this.Rect.Size = new Size(Math.Abs(this.fstSel.X - tempEndPoint.X), Math.Abs(this.fstSel.Y - tempEndPoint.Y));
               this.SelLabel.Text = string.Format("Selection: {0}, {1}px", this.Rect.Size.Width, this.Rect.Size.Height);
               this.panel1.Invalidate();
           }
       }

       /// <summary>
       /// Create Undo action in Menu Bar
       /// </summary>
       private void undoMenuEditItem_Click(object sender, EventArgs e)
       {
           if (this.undoStack.Count != 0)
           {
               this.image = (Bitmap)this.undoStack.Pop().Clone();
               this.panel1.Invalidate();
           }
           else
               MessageBox.Show("No Undo available");
       }

       /// <summary>
       /// Allows to make the rectangle selection
       /// </summary>
       private void panel1_MouseDown(object sender, MouseEventArgs e)
       {
           this.fstSel = e.Location;
           if (this.fstSel.X > this.image.Width)
               this.fstSel.X = this.image.Width;
           if (this.fstSel.Y > this.image.Height)
               this.fstSel.Y = this.image.Height;
           if (this.pickColor == true)
           {
               this.choosenColor = this.image.GetPixel(e.X, e.Y);
               this.pickColor = false;
               this.btnPickColor.CheckState = CheckState.Unchecked;
           }
           if (this.paste == true)
           {
               this.paste = false;
               this.btnPaste.CheckState = CheckState.Unchecked;
               using (Graphics grD = Graphics.FromImage(this.image))
               {
                   grD.DrawImage(this.copyImg, this.fstSel);   //  draws image on destiny bitmap
               }
               this.panel1.Invalidate();
           }
       }

       private void btnErase_Click(object sender, EventArgs e)
       {
           this.erase();
       }

       private void erase()
       {
           this.undoStack.Push((Bitmap)this.image.Clone());
           Graphics gBmp = Graphics.FromImage(this.image);
           Brush brush = new SolidBrush(Color.White);
           gBmp.FillRectangle(brush, this.Rect);
           this.Rect.Size = new Size(0, 0);
           this.panel1.Invalidate();
       }

       private void btnFill_Click(object sender, EventArgs e)
       {
           this.undoStack.Push((Bitmap)this.image.Clone());
           Graphics gBmp = Graphics.FromImage(this.image);
           Brush brush = new SolidBrush(this.choosenColor);
           gBmp.FillRectangle(brush, this.Rect);
           this.Rect.Size = new Size(0, 0);
           this.panel1.Invalidate();
       }

       private void btnPickColor_Click(object sender, EventArgs e)
       {
           this.pickColor = true;
           this.btnPickColor.CheckState = CheckState.Checked;
       }

       private void btnCopy_Click(object sender, EventArgs e)
       {
           this.copyImg = this.image.Clone(this.Rect, System.Drawing.Imaging.PixelFormat.Undefined);
       }

       private void btnPaste_Click(object sender, EventArgs e)
       {
           this.paste = true;
           this.btnPaste.CheckState = CheckState.Checked;   
       }

       private void btnCut_Click(object sender, EventArgs e)
       {
           this.copyImg = this.image.Clone(this.Rect, System.Drawing.Imaging.PixelFormat.Undefined);
           this.erase();
       }

       private void colorMenuFilterItem_Click(object sender, EventArgs e)
       {
           if( Filters.Color(this.image, this.choosenColor))
           {
               this.undoStack.Push((Bitmap)this.image.Clone());
               this.panel1.Invalidate();
           }
       }

       private void gammaMenuFilterItem_Click(object sender, EventArgs e)
       {    
            GamaForm dlg = new GamaForm();
            if (DialogResult.OK == dlg.ShowDialog())
            {
                if (Filters.Gamma(this.image, dlg.red, dlg.green, dlg.blue))
                {
                    this.undoStack.Push((Bitmap)this.image.Clone());
                    this.panel1.Invalidate();
                }
                else
                    MessageBox.Show("Erro!");
            }
       }

       private void invertMenuFilterItem_Click(object sender, EventArgs e)
       {
           if (Filters.Invert(this.image))
           {
               this.undoStack.Push((Bitmap)this.image.Clone());
               this.panel1.Invalidate();
           }
       }

       private void grayscaleMenuFilterItem_Click(object sender, EventArgs e)
       {
           if (Filters.GrayScale(this.image))
           {
               this.undoStack.Push((Bitmap)this.image.Clone());
               this.panel1.Invalidate();
           }
       }

       private void contrastMenuFilterItem_Click(object sender, EventArgs e)
       {
           ParamForm dlg = new ParamForm("Contrast");
           if (DialogResult.OK == dlg.ShowDialog())
           {
               if (Filters.Contrast(this.image, (sbyte)dlg.param))
               {
                   this.undoStack.Push((Bitmap)this.image.Clone());
                   this.panel1.Invalidate();
               }
           }
       }

       private void brightnessMenuFilterItem_Click(object sender, EventArgs e)
       {
           ParamForm dlg = new ParamForm("Brightness");
           if (DialogResult.OK == dlg.ShowDialog())
           {
               if (Filters.Brightness(this.image, dlg.param))
               {
                   this.undoStack.Push((Bitmap)this.image.Clone());
                   this.panel1.Invalidate();
               }
           }
       }

       /// <summary>
       /// Copy yours selection and paste it in the next click 
       /// </summary>
       private Boolean iterImage()
       {


           LockBitmap lockBitmap = new LockBitmap(this.image);
           lockBitmap.LockBits();

           Color compareClr = Color.FromArgb(255, 255, 255, 255);
           for (int y = 0; y < lockBitmap.Height; y++)
           {
               for (int x = 0; x < lockBitmap.Width; x++)
               {
                   if (lockBitmap.GetPixel(x, y) == compareClr)
                   {
                       lockBitmap.UnlockBits();
                       Color c = this.nextColorSeek(x,y);
                       lockBitmap.LockBits();
                       lockBitmap.SetPixel(x, y,c );
                   }
               }
           }
           lockBitmap.UnlockBits();
          

           this.panel1.Invalidate();    
           
           return true;

       }


   


       public Color nextColorSeek(int j, int i ) 
       {
           Color currentPixel = this.image.GetPixel(j, i);
           Color nextColor = new Color();

           if (currentPixel.Equals(Color.FromArgb(255, 255, 255, 255)))
            {                   
                Dictionary<Color, int> neightbours = new Dictionary<Color, int>();
                for (int ii = i - 1; i <= i + 1; ii++)
                {
                    for (int jj = j - 1; j <= j + 1; jj++)
                    {

                        if (ii != 1 && jj != j)
                        {
                            if (!neightbours.ContainsKey(currentPixel))
                            {
                                if (!currentPixel.Equals(Color.White))
                                    neightbours.Add(currentPixel, 1);
                            }
                            else
                                neightbours[currentPixel] = neightbours[currentPixel] + 1;
                        }
                    }
                }
                nextColor = neightbours.First(x => x.Value == neightbours.Values.Max()).Key;
                       
            }
            MessageBox.Show(nextColor.Name);
            return nextColor;
       }
       

       private void clearWhitePointsMenuFilterItem_Click(object sender, EventArgs e)
       {
           this.iterImage();
       }

    }
}